#include<iostream>
#include<stdio.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<time.h>
#include<stdlib.h>
#include<unistd.h>
#include<vector>
#include<cstring>

#define MAXLINE 4096
#define LISTENQ 1024            //监听套接字最大连接数
#define MyPort 8000
#define BufferSize 4111
using namespace std;

struct Buffer
{
	string time;
	string from_name;
	string info_to_send;
	//file
};

//struct Friends
//{
	//string name;
	//struct sockaddr_in addr; //ueser's adderss
	//int sockfd;
//};

struct User
{
    string name;
    string password;
    struct sockaddr_in addr; 
    bool isonline;
    int sockfd;
    string now_chat;
    vector<string> chat_group;
    string file_trans_user_now;
    vector<string> friendlist;
    vector<string> receive_buffer_info;
};

struct Client
{
   int sockfd;
   struct sockaddr_in addr;
   string name;
   string now_chat;
   //vector<string> chat_group;
   string file_trans_user_now;
};

class WeChatServer
{
	vector<User> UserList;
	//int max_socketfd;
	vector<Client> OnlineClient; 
    	//vector<ClientData> OnlineClient;
	private:
		void LogicalProcess(char receive_info[BufferSize], Client &client);
		bool Register(string user_name, string password);
		bool LoginVerification(string user_name, string password); 
		//bool OnlineVerification(string user_name);
		void SendToOneFriend(User& user, string send_info); 
        void SendToAllFriends(User& user, string send_info);
		void AddBuffer(User & user, string info);
		void SendBufferInfo(User & user);
		bool SearchFriend(string search_name);
		void UpdateFriendlist(User & user_request, User& user_response);
		//string getSendMessage(User &user, string kind);
		//void sendMessageToClient(User &user, const char* sendinfo);
		vector<string> Decode(string s);
        void SendFriendListToClient(User &user);
		int getUserPos(string user_name);
	public:
		WeChatServer();
		void start(); 
};

int main()
{
	WeChatServer wechatServer;
	while (1){
        	wechatServer.start();
	}
	return 0;	
}

WeChatServer::WeChatServer(){}

void WeChatServer::start()
{
	//创建套接字
	int listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if ( listenfd < 0 )
		cerr << "socket error" << endl;
	//绑定套接字和地址
	struct sockaddr_in serverAddr;
	bzero(&serverAddr, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
	serverAddr.sin_port = htons(MyPort);
	
	int ret = bind(listenfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
	if ( ret < 0 )
    	{
		cerr << "bind error" << endl;
		close(listenfd);
		return;	
	}
	//监听套接字
	ret = listen(listenfd, LISTENQ);
	if ( ret < 0 ) 
    	{
		cerr << "listen error" << endl;
		close(listenfd);
		return;
	}
    	//int currentClientNum = 0;
	int max_socketfd = listenfd;
    
	fd_set readSet;
    
   	//存放输入的数据
    	char buffer[BufferSize];
    	//存放客户的地址和端口号 
    	string clientInfo;
    
	//使用select实现IO复用
	while (1)
	{
		FD_ZERO(&readSet);
        	FD_SET(listenfd, &readSet);
		for (int i = 0; i < OnlineClient.size(); i++)
		    if (OnlineClient[i].sockfd != 0)
            	    {
		        FD_SET(OnlineClient[i].sockfd, &readSet);
		        if ( OnlineClient[i].sockfd > max_socketfd )
		            max_socketfd = OnlineClient[i].sockfd;
			    }
			if ( select(max_socketfd+1, &readSet, NULL, NULL, 0) < 0 )
		        cerr << "select error" << endl;
        
			if ( FD_ISSET(listenfd, &readSet))
			{
			    struct sockaddr_in clientAddr;
			    bzero(&clientAddr, sizeof(clientAddr));
			    socklen_t clientAddrLen;
			    
			    int connfd = accept(listenfd, (struct sockaddr*)&clientAddr, &clientAddrLen);
			    if(connfd < 0)
			    {
				    cerr << "accept error" << endl;
			    }
			    else
			    {
    				Client client_new;
    				client_new.sockfd = connfd;
    				client_new.addr = clientAddr;
				
				    OnlineClient.push_back(client_new);
			    }
		    }
		
		for (int i = 0; i < OnlineClient.size(); i++)
		{
		    memset(buffer, 0, sizeof(buffer));
		    clientInfo.clear();
		    if(FD_ISSET(OnlineClient[i].sockfd, &readSet))
		    {
		        int ret = recv(OnlineClient[i].sockfd, buffer, sizeof(buffer), 0);
			//printf("%s\n",buffer);
		        if(ret <= 0)
                	{
		            //如果客户端离开聊天室
		   	    //将推出的消息发送给其他人
			    char buffer_to_send[] = "&logout";
			    LogicalProcess(buffer_to_send, OnlineClient[i]);
		            close(OnlineClient[i].sockfd);
		            FD_CLR(OnlineClient[i].sockfd, &readSet);
		            OnlineClient.erase(OnlineClient.begin()+i);
		            i--;//因为上面的删除操作会改变client的长度，所以要i-1	            
		        }
		        else
		        {  
			    if (buffer[ret-1]=='\n')
		            	buffer[ret-1] = '\0';
				cout << ret << endl;
			    //string info(buffer, sizeof(buffer));
			    //cout << info << endl;
			    //cout << info.length()<< endl;
			    //cout << info.size()<< endl;'
				cout << buffer << endl;
		            LogicalProcess(buffer, OnlineClient[i]);
		        }
		    } 
		}
	}	
}


void WeChatServer::LogicalProcess(char receive_info[BufferSize], Client &client)
{
    
    vector<string> info_decode = Decode(receive_info);
    if ( info_decode.size()==0 ) return;
    if ( info_decode[0]=="register" )
    {
	cout << info_decode[1] << endl;
	cout << info_decode[2] << endl;
        if ( Register(info_decode[1], info_decode[2]) )//注册成功
        {
            string info = "&register&Ok";
            send(client.sockfd, info.c_str(), info.size(), 0);
            printf("%s",client.name.c_str());
            printf(" registerOk\n");
        }
        else //此用户已经被注册
        {
            string info = "&register&Fail";
            send(client.sockfd, info.c_str(), info.size(), 0);
            printf("%s",client.name.c_str());
            printf(" registerFail\n");
        }
    }
    else if ( info_decode[0]=="login" )//登录
    {
	cout << info_decode[1] << endl;
	cout << info_decode[2] << endl;
        if ( LoginVerification(info_decode[1], info_decode[2]) )
        {
	    
            client.name = info_decode[1]; 
            string info = "&login&Ok";
            send(client.sockfd, info.c_str(), info.size(), 0);

            User &user = UserList[getUserPos(client.name)];
            user.isonline = true;
            user.sockfd = client.sockfd;
            user.addr = client.addr;

            info = "&friendlogin&"+client.name;
            SendToAllFriends(user, info);

            printf("%s",client.name.c_str());
            printf(" loginOk\n");
        }
        else  //密码错误或者无此用户
        {
            string info = "&login&Fail";
            send(client.sockfd, info.c_str(), info.size(), 0);
            printf("%s",client.name.c_str());
            printf(" loginFail\n");
        }
    }
    else if ( info_decode[0]=="getbuffer")
    {
	User & user = UserList[getUserPos(info_decode[1])];
	SendBufferInfo(user);
    }
    else if ( info_decode[0]=="logout")//登出
    {
	int pos = getUserPos(client.name);
	if ( pos != -1 )
	{
		User &user = UserList[pos];
		user.isonline = false;
		string info = "&logout&"+client.name;
		SendToAllFriends(user, info);
		printf("%s",client.name.c_str());
		printf(" logOut\n");
	}
    }
    else if ( info_decode[0]=="addfriend_response")//是否同意对方好友申请
    {
        //&addfriend_response&request_name&Ok or Fail
        if ( info_decode[2]=="Ok" )
        {
            User &user_request = UserList[getUserPos(info_decode[1])];
            User &user_response = UserList[getUserPos(client.name)];
            UpdateFriendlist(user_request, user_response);
            string info = "&addfriend_response&Ok&"+client.name;
            SendToOneFriend(UserList[getUserPos(info_decode[1])],info);
            printf("%s",client.name.c_str());
            printf(" Ok ");
            printf("%s\n",info_decode[1].c_str());
        }
        else
        {
            string info = "&addfriend_response&Fail&"+client.name;
            SendToOneFriend(UserList[getUserPos(info_decode[1])], info);
            printf("%s",client.name.c_str());
            printf(" Fail ");
            printf("%s\n",info_decode[1].c_str());
        }

    }
    else if ( info_decode[0]=="addfriend_request" )//向他人发送好友申请
    {
        //&addfriend_request&username
        int pos = getUserPos(info_decode[1]);
        
        if ( pos == -1 )
        {
            string info = "&addfriend_response&noThisUser";
            SendToOneFriend(UserList[getUserPos(client.name)], info); 
            printf("%s", info_decode[1].c_str());
            printf(" noThisUser\n");
        }
        else
        {
	    //string info_response = "You has sent a friend application! Please wait for response!";
	    //send(client.sockfd, info_response.c_str(), info_response.length(), 0);
            User &user = UserList[pos];
            string info = "&addfriend_request&"+client.name;
            SendToOneFriend(user, info); 
            printf("%s", info_decode[1].c_str());
            printf(" addFriendRequest\n"); 
        }     
    }
    else if ( info_decode[0]=="buildchat" )
    {
        //&buildchat&username
        int pos = getUserPos(info_decode[1]);
        if ( pos != -1 )
        {
            //发送建立聊天成功的消息
            User &user = UserList[getUserPos(client.name)];
            string info = "&buildchat&Ok";
            send(client.sockfd, info.c_str(), info.size(), 0);
            //User &user = UserList[getUserPos(client.name)];
            user.now_chat = info_decode[1];
            //user_chat.now_chat = user;
            printf("%s ", info_decode[1].c_str());
            printf("%s ", client.name.c_str());
            printf("buildChatOk\n");
        }
        else
        {
            //发送建立聊天失败的消息，原因是是没有这个用户
            string info = "&buildchat&Fail";
            send(client.sockfd, info.c_str(), info.size(), 0);
            printf("%s ", info_decode[1].c_str());
            printf("%s ", client.name.c_str());
            printf("buildChatFail\n");
        }
    }
    else if ( info_decode[0]=="sendinfo" )
    {
        //&sendinfo&info
	User &user = UserList[getUserPos(client.name)];
        User &to_user = UserList[getUserPos(user.now_chat)];
	string info = "&sendinfo&" + client.name + "&" + info_decode[1];
        SendToOneFriend(to_user, info);
	printf("%s", user.name.c_str());
	printf("%s", to_user.name.c_str());
        printf("%s\n", info_decode[1].c_str());
    }
    else if ( info_decode[0]=="getFriend")
    {
        User &user = UserList[getUserPos(client.name)];
        SendFriendListToClient(user);
    }
    else if ( info_decode[0]=="filetrans_confirm")              //filetrans_confirm&to_user_name&filename
    {
        User &to_user =  UserList[getUserPos(info_decode[1])];
        client.file_trans_user_now = info_decode[1];
        string info = "&filetrans_confirm&"+client.name+"&"+info_decode[2];
        SendToOneFriend(to_user, info);
    }
    else if ( info_decode[0]=="filetrans_response")          //filetrans_confirm&to_user_name&Ok or Fail
    {
        User &to_user =  UserList[getUserPos(info_decode[1])];
        string info = "&filetrans_response&"+client.name+"&"+info_decode[2];
        SendToOneFriend(to_user, info);
    }
    else if ( info_decode[0]=="ffffffffffff")               //filetrans_confirm&to_user_name&file content
    {
        User &to_user =  UserList[getUserPos(client.file_trans_user_now)];
	char info_to_send[BufferSize-14];
	for (int i = 0; i < BufferSize-14; i++)
		info_to_send[i] = receive_info[i+14];
	
	cout << info_to_send << endl;
        send(to_user.sockfd, info_to_send, BufferSize-14, 0);
    }
    else if ( info_decode[0]=="buildgroup")
    {
	User &user =  UserList[getUserPos(client.name)];
	user.chat_group.clear();
	for (int i = 1; i < info_decode.size(); i++)
	    user.chat_group.push_back(info_decode[i]);
	string info = "&buildgroup&Ok";
	SendToOneFriend(user, info);
    }
    else if ( info_decode[0]=="sendgroupinfo")
    {
        //&sendinfo&info
	User &user = UserList[getUserPos(client.name)];
	for ( int i = 0; i < user.chat_group.size(); i++ )
	{
		User &to_user = UserList[getUserPos(user.chat_group[i])];
		string info = "&sendinfo&" + client.name + "&" + info_decode[1];
		SendToOneFriend(to_user, info);
	}
    }
}

bool WeChatServer::Register(string user_name, string password){
    for (int i = 0; i < UserList.size(); i++)
        if ( UserList[i].name == user_name )
            return false;
    User user_new;
    user_new.name = user_name;
    user_new.password = password;
    user_new.isonline = false;
    UserList.push_back(user_new);
    return true;
}

bool WeChatServer::LoginVerification(string user_name, string password){
    for (int i = 0; i < UserList.size(); i++)
	{
		if ( UserList[i].name == user_name )
		    if ( UserList[i].password == password )
		        return true;
		    else 
		        return false;     
	}      
    return false;
}

//bool WeChatServer::OnlineVerification(string user_name){}

void WeChatServer::SendToOneFriend(User& user, string send_info){
    if ( user.isonline )
        send(user.sockfd, send_info.c_str(), send_info.size(), 0);
    else AddBuffer(user, send_info);
}

void WeChatServer::SendToAllFriends(User& user, string send_info){
    for ( int i = 0; i < user.friendlist.size(); i++)
        if ( UserList[getUserPos(user.friendlist[i])].isonline )
            send(UserList[getUserPos(user.friendlist[i])].sockfd, send_info.c_str(), send_info.size(), 0);
}

void WeChatServer::AddBuffer(User & user, string info){
    //Buffer new_buffer;
    //new_buffer.from_name = from_user_name;
    //new_buffer.info_to_send = info;
    user.receive_buffer_info.push_back(info);
}

void WeChatServer::SendBufferInfo(User & user){
    for ( int i = 0; i < user.receive_buffer_info.size(); i++ )
    {
        //string info = "&bufferinfo&"+user.receive_buffer_info[i].from_name+"&"
                      //+user.receive_buffer_info[i].info_to_send;
        SendToOneFriend(user, user.receive_buffer_info[i].c_str());
	printf("buffer");
	printf("%s\n", user.receive_buffer_info[i].c_str());
    }  
    user.receive_buffer_info.clear();
}

bool WeChatServer::SearchFriend(string search_name){
    
}

void WeChatServer::UpdateFriendlist(User & user_request, User& user_response){
    user_request.friendlist.push_back(user_response.name);
    user_response.friendlist.push_back(user_request.name);

    // string info_to_request = "&addfriend_response&Ok&"+user_response.name;
    // send(user_request.sockfd, info_to_request.c_str(), info_to_request.length(), 0);
    // string info_to_response = "&addfriend_response&Ok&"+user_request.name;
    // send(user_response.sockfd, info_to_response.c_str(), info_to_response.length(), 0);
}

int WeChatServer::getUserPos(string user_name){
    for (int i = 0; i < UserList.size(); i++)
        if ( UserList[i].name == user_name )
            return i;
    return -1;
}

vector<string> WeChatServer::Decode(string s)
{
    vector<string> s_decode;
    for (int i = s.size(); i >= 0; i--)
        if ( s[i]=='&' )
        {
            s_decode.insert(s_decode.begin(),s.substr(i+1,s.size()-i-1));
            s = s.substr(0,i);
        }
    return s_decode;
}

void  WeChatServer::SendFriendListToClient(User &user)
{
    string info = "&friendlist";
    for (int i = 0; i < user.friendlist.size(); i++)
        info = info + "&" + user.friendlist[i];
    send(user.sockfd, info.c_str(), info.size(), 0);
}














